package com.why.cachecloud.service.server.nmon;

import com.why.cachecloud.service.server.data.OS;
import com.why.cachecloud.service.server.data.OSInfo;
import com.why.cachecloud.service.ssh.SSHTemplate;
import com.why.cachecloud.util.NMONFileFactory;
import com.why.cachecloud.util.OSFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.File;

/**
 * 服务器监控脚本服务(nmon识别和监控)
 */
@Component
public class NMONService {
    private static final Logger logger = LoggerFactory.getLogger(NMONService.class);
    //获取系统版本位数命令
    public static final String OS_INFO_CMD = "/bin/uname -a; /bin/cat /etc/issue";
    //nmon路径
    public static final String NMON_DIR = "/opt/cachecloud/soft/";
    //nmon文件名
    public static final String NMON = "nmon";
    //nmon完整路径
    public static final String NMON_FILE = NMON_DIR + NMON;
    //获取nmon版本
    public static final String NMON_VERSION = "[ -e \"" + NMON_FILE + "\" ] && " + NMON_FILE + " -V";
    //nmon输出的结果文件
    public static final String NMON_LOG = "/tmp/nmon.log";
    //nmon输出的老结果文件
    public static final String NMON_OLD_LOG = "/tmp/nmon.old.log";
    //tcp输出的结果文件
    public static final String SOCK_LOG = "/tmp/sock.log";
    //ulimit输出的结果文件
    public static final String ULIMIT_LOG = "/tmp/ulimit.log";

    //nmon监控启动
    public static final String START_SERVER_COLLECT = NMON_FILE + " -F " + NMON_LOG + " -s0 -c1;" +
            "/bin/grep TCP /proc/net/sockstat > " + SOCK_LOG +
            ";ulimit -n -u > " + ULIMIT_LOG ;
    //创建nmon路径
    public static final String MK_NMON_DIR = "/bin/mkdir -p /opt/cachecloud/soft/";

    /**
     * 启动nmon收集系统状况
     *
     * @param ip
     * @param session
     * @return @OSInfo 收集到的操作系统信息
     */
    public OSInfo start(String ip, SSHTemplate.SSHSession session) {
        SSHTemplate.Result startCollectResult = session.executeCommand(START_SERVER_COLLECT);
        if (!startCollectResult.isSuccess()) {
            logger.error("start nmon " + ip + " err:" + startCollectResult.getResult(),
                    startCollectResult.getExcetion());
            //执行命令没有发生异常，则nmon可能不存在或有问题
            if (startCollectResult.getExcetion() == null) {
                //尝试处理出错信息
                return initNmon(ip, session);
            }
        }
        return null;
    }

    /**
     * 尝试修复启动失败的错误
     *
     * @param ip
     * @param session
     */
    private OSInfo initNmon(String ip, SSHTemplate.SSHSession session) {
        //获取nmon版本
        String version = getNMONVersion(ip, session);
        //获取操作系统原始信息
        OSInfo osInfo = getOSInfo(ip, session);
        OS os = null;
        //nmon文件不存在，需要根据操作系统识别是否支持
        if (null == version) {
            logger.warn("{} not exist {}", ip, NMON_FILE);
            //将原始信息转换为可识别的操作系统
            os = OSFactory.getOS(osInfo);
        } else {
            //nmon存在，但是版本有问题，此时不应该再判断系统信息了，直接用默认的
            logger.warn("{} {} version err:" + version, ip, NMON_FILE);
            os = OSFactory.getDefaultOS(osInfo);
        }
        if (os == null) {
            logger.error("unkonw os info={}", osInfo);
            return null;
        }
        //获取nmon文件
        File nmonFile = NMONFileFactory.getNMONFile(os);
        if (nmonFile == null) {
            logger.warn("{} no corresponding nmon file", os);
            nmonFile = NMONFileFactory.getNMONFile(OSFactory.getDefaultOS(osInfo));
        }
        //将nmon文件传输至服务器
        sendNMONToServer(ip, session, nmonFile);

        return osInfo;
    }

    /**
     * 获取nmon文件版本
     *
     * @param ip
     * @param session
     * @return 存在返回版本，不存在返回null, 执行错误返回异常
     */
    private String getNMONVersion(String ip, SSHTemplate.SSHSession session) {
        SSHTemplate.Result nmonVersionResult = session.executeCommand(NMON_VERSION);
        if (nmonVersionResult.isSuccess()) {
            return nmonVersionResult.getResult();
        } else {
            logger.error(NMON_VERSION + " err:" + nmonVersionResult.getResult(), nmonVersionResult.getExcetion());
        }
        return null;
    }

    /**
     * 获取操作系统信息
     *
     * @param ip
     * @param session
     * @return OSInfo
     */
    private OSInfo getOSInfo(String ip, SSHTemplate.SSHSession session) {
        final OSInfo osInfo = new OSInfo();
        session.executeCommand(OS_INFO_CMD, new SSHTemplate.DefaultLineProcessor() {
            @Override
            public void process(String line, int lineNum) throws Exception {
                switch (lineNum) {
                    case 1:
                        osInfo.setUname(line);
                        break;
                    case 2:
                        osInfo.setIssue(line);
                        break;
                    default:
                        break;
                }
            }
        });
        return osInfo;
    }


    /**
     * 将nmon文件scp到服务器上
     *
     * @param ip
     * @param session
     * @param nmonFile
     */
    private void sendNMONToServer(String ip, SSHTemplate.SSHSession session, File nmonFile) {
        SSHTemplate.Result mkResult = session.executeCommand(MK_NMON_DIR);
        if (!mkResult.isSuccess()) {
            logger.error("mkdir err:" + mkResult.getResult(), mkResult.getExcetion());
            return;
        }
        SSHTemplate.Result scpRst = session.scpToFile(nmonFile.getAbsolutePath(), NMON, NMON_DIR);
        if (scpRst.isSuccess()) {
            logger.info("scp {} to {} success", nmonFile.getAbsolutePath(), ip);
        } else {
            logger.error("scp to " + ip + " err", scpRst.getExcetion());
        }
    }
}
